/**
 * @author Tobias Boehm
 *
 * 28.03.2011
 */
package org.anddev.andengine.extension.tbsengine.resource;

import java.util.HashMap;
import java.util.HashSet;

import org.anddev.andengine.extension.tbsengine.gameobject.Unit;
import org.anddev.andengine.extension.tbsengine.gameobject.ability.AbsAbility;


/**
 * This is an ability for {@link Unit}s to consume resources.
 * 
 * @author Tobias Boehm
 *
 */
public class ResourceConsumerAbility extends AbsAbility {

	private final HashSet<ResourceAccount> mResourceAccounts;
	
	public ResourceConsumerAbility(final String pName, final String pDescription, final int pIconTileID){
		super(pName, pDescription, pIconTileID);
				
		this.mResourceAccounts = new HashSet<ResourceAccount>();
	}
	
	public synchronized boolean consumeResources(final HashMap<AbsBaseResourceType,Integer> pResourcesAmountNeeded){
		
		// Count and Check
		if(resourcesAvailable(pResourcesAmountNeeded)){
			
			// Consume
			for(AbsBaseResourceType currentRessourceType : pResourcesAmountNeeded.keySet()){
				
				int amountNeededLeft = pResourcesAmountNeeded.get(currentRessourceType);
				
				for(ResourceAccount currentAccount : this.mResourceAccounts){
					
					if(currentAccount.getResourceType() == currentRessourceType){
					
						final int availableAmount = currentAccount.getCreditLine();
						
						if(availableAmount >= amountNeededLeft){
							
							try {
								currentAccount.transact( -amountNeededLeft );
								amountNeededLeft = 0;
								break;
							} catch (ResourceAccountLimitExceededException e) {}
						
						}else{
							
							try {
								currentAccount.transact( -availableAmount);
								amountNeededLeft -= availableAmount;
							} catch (ResourceAccountLimitExceededException e) {}
						}
					}
				}
				
				// ReCheck (maybe there was some asynchronous change to one of the account balances - very EVIL!)
				if(amountNeededLeft > 0){
					
					throw new IllegalStateException();
				}
			}
			
			// Accept
			return true;
					
		}else{
			
			// Reject
			return false;
		}
	}
		
	public boolean resourcesAvailable(final HashMap<AbsBaseResourceType,Integer> pResourcesAmountNeeded){
		
		final HashMap<AbsBaseResourceType,Integer> resourcesAvailableCounter = new HashMap<AbsBaseResourceType, Integer>();
		
		// Count and Check
		for(AbsBaseResourceType currentResourceType : pResourcesAmountNeeded.keySet()){
			
			resourcesAvailableCounter.put(currentResourceType, 0);
			
			// Count
			for(ResourceAccount currentAccount : this.mResourceAccounts){
			
				if(currentAccount.getResourceType() == currentResourceType){
					
					resourcesAvailableCounter.put(currentResourceType, resourcesAvailableCounter.get(currentResourceType) + currentAccount.getCreditLine());
				}
			}
						
			// Check
			if(pResourcesAmountNeeded.get(currentResourceType) > resourcesAvailableCounter.get(currentResourceType)){
				
				return false;
			}
		}
						
		return true;
	}
}
